﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.IO;
using System.Web.Mvc;
using StockPredictor.Models;
using System.Configuration;

namespace StockPredictor.App_Start
{
    public class StockValuation
    {
        #region GetStocksToBuy
        /// <summary>
        /// Return the recommended list of stocks to buy 
        /// </summary>
        /// <param name=""></param>
        public static List<CurrentStock> GetStocksToBuy(string userName)
        {
            UserPreferencesUtilities.GetUserPreferencesRecordsForUser(userName);

            string[] searchString = ConfigurationManager.AppSettings["UsStocksToEvaluate"].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            // retrieve stock data
            List<CurrentStock> stocks = YahooFinance.GetCurrentStockData(searchString, userName);
            List<CurrentStock> stocksToReturn = new List<CurrentStock>();
            List<HistoricalStock> historicalYearlyStocks = new List<HistoricalStock>();

            double peRatio;
            double bid = 0;
            double ask = 0;
            double spread;

            int stocksWithIncorrectHistory = 0;

            foreach (var stock in stocks)
            {
                peRatio = stock.PERatio;
                bid = stock.Bid;
                ask = stock.Ask;

                spread = CalculateSpreadPrcntg(bid, ask);

                if (PeRatioIsGood(peRatio, 1) == 1)
                {
                    //if (SpreadIsGood(spread) == 1)
                    //{
                        historicalYearlyStocks = GetHistoricalYearlyStocks(stock.Symbol);

                        if (historicalYearlyStocks.Count() > 1) //If for some reason the data isn't available historically for a year before discount this stock
                        {
                            if (EpsIsGood(historicalYearlyStocks, 1) == 1)
                            {
                                stocksToReturn.Add(stock);
                            }
                        }
                        else 
                        {
                            stocksWithIncorrectHistory++;
                        }
                    //}
                }

            }
            return stocksToReturn;

        }

        #endregion GetStocksToBuy

        #region GetStocksToSell
        /// <summary>
        /// Return the recommended list of stocks to sell 
        /// </summary>
        /// <param name=""></param>
        public static List<CurrentStock> GetStocksToSell(string userName)
        {
            string[] searchString = ConfigurationManager.AppSettings["UsStocksToEvaluate"].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            // retrieve stock data
            List<CurrentStock> stocks = YahooFinance.GetCurrentStockData(searchString, userName);
            List<CurrentStock> stocksToReturn = new List<CurrentStock>();
            List<HistoricalStock> historicalYearlyStocks = new List<HistoricalStock>();
            int stocksWithIncorrectHistory =  0;

            double peRatio;

            foreach (var stock in stocks)
            {
                peRatio = stock.PERatio;

                if (PeRatioIsGood(peRatio, 1) == 0)
                {
                    historicalYearlyStocks = GetHistoricalYearlyStocks(stock.Symbol);

                    if (historicalYearlyStocks.Count() > 1) //If for some reason the data isn't available historically for a year before discount this stock
                    {
                        if (EpsIsGood(historicalYearlyStocks, 1) == 0)
                        {
                            stocksToReturn.Add(stock);
                        }
                    }
                    else 
                    {
                        stocksWithIncorrectHistory++;
                    }

                }

            }
            return stocksToReturn;

        }

        #endregion GetStocksToSell

        #region PeRatioIsGood
        /// <summary>
        /// Check PE Ratio 
        /// </summary>
        /// <param name="ActualPeRatio">Pe Ration</param>
        public static int PeRatioIsGood(double ActualPeRatio, int StocksToBuy)
        {
            double PeRatioUsedForStocksToReturn;

            if (StocksToBuy == 1)
                if (UserPreferencesUtilities.userPreferencesExist == 1)
                    PeRatioUsedForStocksToReturn = UserPreferencesUtilities.userPreferencePeRatio;
                else
                    PeRatioUsedForStocksToReturn = Convert.ToDouble(ConfigurationManager.AppSettings["PeRatioUsedForStocksToBuy"]);
            else
                PeRatioUsedForStocksToReturn = Convert.ToDouble(ConfigurationManager.AppSettings["PeRatioUsedForStocksToSell"]);

            if (ActualPeRatio > PeRatioUsedForStocksToReturn)
                return 0;
            else
                return 1;
        }

        #endregion PeRatioIsGood

        #region CalculateSpreadPrcntg
        /// <summary>
        /// Spread % = (Ask - Bid)/ Ask * 100%  
        /// </summary>
        /// <param name="Bid">Bid</param>
        /// <param name="Ask">Ask</param>
        public static double CalculateSpreadPrcntg(double Bid, double Ask)
        {
            double Spread = 0;
            double SpreadNum = 0;
            double SpreadPrcntg = 0;

            SpreadNum = Ask - Bid;
            Spread = SpreadNum / Ask;
            SpreadPrcntg = Spread * 100;

            return SpreadPrcntg;
        }

        #endregion CalculateSpreadPrcntg

        #region SpreadIsGood
        /// <summary>
        /// Check Spread 
        /// </summary>
        /// <param name="Spread">Spread</param>
        public static int SpreadIsGood(double Spread)
        {
            double SpreadUsedForStocksToBuy = 0;

            if (UserPreferencesUtilities.userPreferencesExist == 1)
                SpreadUsedForStocksToBuy = UserPreferencesUtilities.userPreferenceSpreadPrcntg;
            else
                SpreadUsedForStocksToBuy = Convert.ToDouble(ConfigurationManager.AppSettings["SpreadUsedForStocksToBuy"]);

            if (Spread > SpreadUsedForStocksToBuy)
                return 0;
            else
                return 1;
        }

        #endregion SpreadIsGood

        #region GetHistoricalYearlyStocks
        /// <summary>
        /// Get stocks over past 5 years
        /// </summary>
        /// <param name="ActualPeRatio">Stock symbol</param>
        public static List<HistoricalStock> GetHistoricalYearlyStocks(string stockSymbol)
        {
            //Get Historical Stock Info
            List<HistoricalStock> historicalStocks = YahooFinance.GetHistoricalStockData(stockSymbol);
            List<HistoricalStock> historicalYearlyStocks = new List<HistoricalStock> { };

            List<string> stocksWithGoodEps = new List<string> { };
            DateTime TradeDateForEpsValuation = DateTime.Today;
            int dayOfWeek = (int)System.DateTime.Now.DayOfWeek;
            
            for (int i = 0; i < 2; ++i)
            {
                //Need to loop because data is sporadic.  Sometimes is falls on the weekend and skips random days
                for (int j = 0; j < 7; ++j)
                {
                    HistoricalStock hs = historicalStocks.Find(delegate(HistoricalStock e) { return e.TradeDate == TradeDateForEpsValuation; });

                    if (hs == null)
                    {
                        TradeDateForEpsValuation = TradeDateForEpsValuation.AddDays(-1);
                    }
                    else 
                    {
                        historicalYearlyStocks.Add(hs);
                        j = 7; //exit the loop because the historical stock was found
                    }                  

                }
                TradeDateForEpsValuation = TradeDateForEpsValuation.AddYears(-1);
                dayOfWeek = (int)TradeDateForEpsValuation.DayOfWeek;
            }
            return historicalYearlyStocks;

        }

        #endregion GetHistoricalYearlyStocks

        #region EpsIncreased
        /// <summary>
        /// Check that EPS has risen by configured percentage 
        /// </summary>
        /// <param name="yearOneEps">EPS values</param>
        public static int EpsIncreased(double yearOneEps, double yearTwoEps, int StocksToBuy)
        {
            double num;
            double denom;
            double increase;
            double increasePrcntg;

            //testing
            //yearOneEps = 2;
            //yearTwoEps = 50;

            num = yearTwoEps - yearOneEps;
            denom = yearOneEps;

            increase = num / denom;
            increasePrcntg = increase * 100;

            double EpsPrcntgUsedForStocksToReturn;


            if (UserPreferencesUtilities.userPreferencesExist == 1)
                EpsPrcntgUsedForStocksToReturn = 10;

            if (StocksToBuy == 1)
                if (UserPreferencesUtilities.userPreferencesExist == 1)
                    EpsPrcntgUsedForStocksToReturn = UserPreferencesUtilities.userPreferenceEpsPrcntg;
                else
                    EpsPrcntgUsedForStocksToReturn = Convert.ToDouble(ConfigurationManager.AppSettings["EpsPrcntgIncreasePerYearUsedForStocksToBuy"]);
            else
                EpsPrcntgUsedForStocksToReturn = Convert.ToDouble(ConfigurationManager.AppSettings["EpsPrcntgIncreasePerYearUsedForStocksToSell"]);

            if (increasePrcntg >= EpsPrcntgUsedForStocksToReturn)
                return 1;
            else
                return 0;
        }

        #endregion EpsIncreased


        #region EpsIsGood
        /// <summary>
        /// Check that EPS has risen over past 5 years 
        /// </summary>
        /// <param name="ActualPeRatio">Stock symbol</param>
        public static int EpsIsGood(List<HistoricalStock> historicalYearlyStocks, int stocksToBuy)
        {

            for (int i = 0; i < Convert.ToInt32(ConfigurationManager.AppSettings["HistoricalStockTotalYears"]); ++i)
            {
                if (EpsIncreased(historicalYearlyStocks[i].EPS, historicalYearlyStocks[i + 1].EPS, stocksToBuy) == 0)
                    return 0;
            }

            return 1;
        }

        #endregion EpsIsGood

    }
}